/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package edu.isi.pegasus.planner.subworkflow.scheduler.implementation;

import edu.isi.pegasus.planner.classes.ADag;
import edu.isi.pegasus.planner.classes.PegasusBag;
import edu.isi.pegasus.planner.subworkflow.partitioner.DAXAbstraction;
import edu.isi.pegasus.planner.subworkflow.partitioner.SiteAbstraction;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;

/**
 *
 * @author wchen
 */
public class HEFT extends ListScheduler{




    private Map weight2;
    private Map AFT;
    //private Map avail;
    private Map EST;
    private Map EFT;
    private int numOfslot;
    private Map job2rank;
    private Map rank2job;
    private double casedEFTTime;

    private LinkedList runQ;
    private LinkedList doneQ;
    //private Map avail;
    private Map ECT;
    private Map FAT;
//    private Map weight;
//    private Map getChildrenMap;
//    private Map getParentsMap;
//    private DAXAbstraction headNode;
//    private DAXAbstraction rearNode;
//    private Map mSiteList;
    private Map mSiteFile;

    //private Map mSitePureSize;

    public HEFT(ADag dag, PegasusBag bag)
    {
        super(dag,bag);
        runQ = new LinkedList<DAXAbstraction>();
        doneQ = new LinkedList<DAXAbstraction>();
//        getChildrenMap = new HashMap<String, ArrayList>();
//        getParentsMap   = new HashMap<String, ArrayList>();
        //avail = new HashMap<SiteAbstraction, Double>();
//        weight = new HashMap<DAXAbstraction, Map>();
        ECT = new HashMap<String, Double>();
        FAT = new HashMap<String, Double>();
//        mSiteList = new HashMap<SiteAbstraction, ArrayList>();
        weight2 = new HashMap<Double, Double>();
        AFT = new HashMap<DAXAbstraction, Double>();
        EST = new HashMap<DAXAbstraction, Map>();
        

        
    }

    private double getAFT(DAXAbstraction bigDax)
    {


         if(AFT.containsKey(bigDax))
             return (Double)AFT.get(bigDax);
        double runtime1 = 1e8;//big enough
        SiteAbstraction slot = null;
        for(int j = 0; j < mSiteIndex.size(); j ++)
        {
            SiteAbstraction site = (SiteAbstraction)mSiteIndex.get(j);
            //double runtime = (Double)weight.get(rank);
            double runtime = getweight(bigDax, site);

            double communication = getSitePureSize(bigDax)/10e6 + 50.0;

            double runtime2  = runtime + getEST(bigDax  , site) + communication;

            System.out.println("Estimated Runtime:" + (runtime+runtime2) +  " for " + bigDax.adag.getName());
            if(runtime2 >= 1e8)
                System.err.println("Runtime of this job is too large\n");
            if(runtime2 < runtime1)
            {
                double requiredSpace = getSiteSize(site, bigDax);
                if(site.space >= requiredSpace *0.95)
                {
                    runtime1 = runtime2;
                    slot = site;
                }
            }

        }
        //double ava = getavail(slot);
        //avail.put(slot, runtime1);
        setavail(slot, runtime1);
        AFT.put(bigDax, runtime1);
        setSiteList(slot, bigDax);
        

            if(bigDax.equals(headNode)||bigDax.equals(rearNode))
            {

            }
            else
            {
                /*Warning*/
                //site.space -= bigDax.size;

                String filename = bigDax.adag.getName() + ".xml";
                String mName = bigDax.adag.getName();
                addDAXJob2DAG(filename, mName , slot.name);
                System.out.println("dax " + mName + " with size " + bigDax.size + " with degree " + bigDax.degree +
                " is mapped to " + slot.name + " with slot " + slot.slot);
            }

        return runtime1;
    }

    private double getEST(DAXAbstraction bigDax, SiteAbstraction site)
    {
        if(!EST.containsKey(bigDax))
            EST.put(bigDax, new HashMap<SiteAbstraction, Double>());
        Map map = (HashMap)EST.get(bigDax);

        double value = 0.0;
        if(!map.containsKey(site))
        {
            double maxAFT = getavail(site);
            if(!getParentsMap.containsKey(bigDax.adag.getName()))
                getParentsMap.put(bigDax.adag.getName(), new ArrayList<String>());
            ArrayList list = (ArrayList)getParentsMap.get(bigDax.adag.getName());

            for(Iterator it = list.iterator(); it.hasNext();)
            {
//                edu.isi.pegasus.planner.classes.Job parent =
//                (edu.isi.pegasus.planner.classes.Job)it.next();

                DAXAbstraction parent = (DAXAbstraction)mDAXID2DAX.get((String)it.next());
                //double prank = (Double)job2rank.get(parent);
                double aft = getAFT(parent);
                //aft += getSitePureSize(bigDax)/10e6 + 50.0;//This is really simpliefied for CyberShake
                //System.out.println("Estimated Communication cost " + getSitePureSize(bigDax)/10e6);
                //System.out.println("Estimated AFT")

                //actually should cosider the communication sot

                if(aft > maxAFT) maxAFT = aft;
            }
            value = maxAFT;
            map.put(site, value);
        }
        return value;
    }

    @Override
    public void schedule()
    {
        //DAXAbstraction headNode = getHeadNode();
        //Fake();
        getHeadNode();

        double makespan = getAFT(rearNode);
        

    }


}
